//      EngineVideo.cpp
//      
//      Copyright 2011 Philipp Müller <xi-vr@xi-intersection.net>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include "EngineVideo.hpp"

#include <iostream>

#include <SDL.h>
#include <SDL_opengl.h>

/**********************************************************************
 * Öffentliche Methoden                                               *
 **********************************************************************/

EngineVideo::EngineVideo(Config &config) : config(config) {
	std::cout << "DEBUG: EngineVideo Constructor\n";
	
	init_sdl_video();
	init_opengl();
}

EngineVideo::~EngineVideo(void) {
	std::cout << "DEBUG: EngineVideo Destructor\n";
}

/**********************************************************************
 * Geschützte Methoden                                                *
 **********************************************************************/

void EngineVideo::init_opengl(void)  {
	/*================================================================*/
	/* Setting up OpenGL                                              */
	
	glShadeModel(GL_SMOOTH);
	
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	
	glEnable(GL_DEPTH_TEST);
	//glEnable(GL_CULL_FACE);
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_POINT_SMOOTH);
	
	glDepthFunc(GL_LEQUAL);
	glCullFace(GL_BACK);
	glLineWidth(2.0);
	
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void EngineVideo::init_sdl_video(void) {
	/*================================================================*/
	/* r stores results for SetAttribute                              */
	int r = 0;
	
	/*================================================================*/
	/* Enable Double-Buffering on OpenGL-Side                         */
	
	r -= SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	
	/*================================================================*/
	/* Setting up buffer depths                                       */
	
	r -= SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,  32);
	r -= SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,   16);
	r -= SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,  8);
	
	r -= SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   8);
	r -= SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	r -= SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  8);
	r -= SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	
	r -= SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,   8);
	r -= SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8);
	r -= SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE,  8);
	r -= SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8);
	
	r -= SDL_GL_SetAttribute(SDL_GL_STEREO, 0);
	
	r -= SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
	r -= SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
	
	/*================================================================*/
	/* Checking whether arguments got set correctly or not            */
	
	if (r != 0) {
		std::cerr << "SDL GL initialization failed:\n " << SDL_GetError() << "\n";
		abort();
	}
	
	/*================================================================*/
	/* Setting up output view                                         */
	
	std::cout << "DEBUG: Video-Init: " << this->config.video.resX << " : " << this->config.video.resY << " << " << (int)this->config.video.depth << ";\n";
	
	int flags = this->calc_sdl_flags();
	this->surface = SDL_SetVideoMode(this->config.video.resX, this->config.video.resY, this->config.video.depth, flags);
	
	/*================================================================*/
	/* Additional Informations for eventual window managers           */
	
	SDL_WM_SetCaption("Xi-VR", "Xi-VR");
	/* SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"), NULL); */
	SDL_WM_SetIcon(NULL, NULL);
}


void EngineVideo::updateVideoInformation(void) {
	/*================================================================*/
	/* Try to get something about our hardware                        */
	
	this->videoInformation = SDL_GetVideoInfo();
	if (!this->videoInformation) {
		std::cerr << "Getting video information failed:\n " << SDL_GetError() << "\n";
		abort();
	}
}

int EngineVideo::calc_sdl_flags() {
	int flags;
	
	this->updateVideoInformation();	
	
	/*================================================================*/
	/* Initial set of flags                                           */
	
	flags  = SDL_OPENGL;          /* Enable OpenGL in SDL */
	flags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
	flags |= SDL_HWPALETTE;       /* Store the palette in hardware */
	
	/*================================================================*/
	/* This checks to see if surfaces can be stored in memory         */
	
	if (this->videoInformation->hw_available) {
		flags |= SDL_HWSURFACE;
	}
	else {
		flags |= SDL_SWSURFACE;
	}
	
	/*================================================================*/
	/* This checks if hardware blits can be done                      */
	
	if (this->videoInformation->blit_hw) {
		flags |= SDL_HWACCEL;
	}
	
	/*================================================================*/
	/* Did the user wanted to be in fullscreen?                       */
	
	if (this->config.video.fullscreen) {
		flags |= SDL_FULLSCREEN;
	}
	else {
		flags |= SDL_RESIZABLE; /* Enable window resizing */
	}
	
	return flags;
}
